﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Kokomo.Mirror.CliMetadata
{
	public class ParentChildRelationship<TParent, TChild>
		where TParent : IMetadataRow, new()
		where TChild : IMetadataRow, new()
	{
		public ParentChildRelationship(
			MetadataTable<TParent> parentTable,
			MetadataTable<TChild> childTable,
			Converter<TParent, int> firstChildDelegate
			)
		{
			if (parentTable == null) throw new ArgumentNullException("parentTable");
			if (childTable == null) throw new ArgumentNullException("childTable");
			if (firstChildDelegate == null) throw new ArgumentNullException("firstChildDelegate");

			this.ParentTable = parentTable;
			this.ChildTable = childTable;
			this.FirstChildDelegate = firstChildDelegate;
		}

		public MetadataTable<TParent> ParentTable { get; private set; }
		public MetadataTable<TChild> ChildTable { get; private set; }
		public Converter<TParent, int> FirstChildDelegate { get; private set; }

		public MetadataRowRange<TChild> GetChildRangeFor(int parentRowNumber)
		{
			TParent parentRow = this.ParentTable[parentRowNumber - 1];
			int firstChildRowNumber = this.FirstChildDelegate(parentRow);
			int listLength;
			if (parentRowNumber < this.ParentTable.Rows.Count)
			{
				TParent nextRow = this.ParentTable[parentRowNumber];
				int nextListStart = this.FirstChildDelegate(nextRow);
				listLength = nextListStart - firstChildRowNumber;
			}
			else
			{
				listLength = this.ChildTable.Rows.Count - firstChildRowNumber + 1;
			}

			MetadataRowRange<TChild> range = new MetadataRowRange<TChild>(
				parentRowNumber,
				this.ChildTable,
				firstChildRowNumber,
				listLength
				);

			return range;
		}
		public int FindOwnerRowNumber(int childRowNumber)
		{
			int min = 1;
			int max = this.ParentTable.Rows.Count;
			int i = 0;

			while (max >= min)
			{
				i = (min + max) / 2;
				MetadataRowRange<TChild> range = this.GetChildRangeFor(i);
				bool contains = range.Contains(childRowNumber);
				if (contains) return i;

				if (childRowNumber < range.FirstRowNumber)
				{
					max = i - 1;
				}
				else
				{
					min = i + 1;
				}
			}

			return 0;
		}

	}
}
